package org.jetlinks.community.device.web;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.hswebframework.ezorm.rdb.mapping.defaults.SaveResult;
import org.hswebframework.web.api.crud.entity.PagerResult;
import org.hswebframework.web.api.crud.entity.QueryOperation;
import org.hswebframework.web.api.crud.entity.QueryParamEntity;
import org.hswebframework.web.api.crud.entity.TreeSupportEntity;
import org.hswebframework.web.authorization.annotation.*;
import org.hswebframework.web.crud.web.reactive.ReactiveServiceCrudController;
import org.jetlinks.community.device.entity.Region;
import org.jetlinks.community.device.entity.RegionDeviceEntity;
import org.jetlinks.community.device.service.RegionDeviceService;
import org.jetlinks.community.device.service.RegionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.function.Function;

@RestController
@RequestMapping("region")
@Slf4j
@Tag(name = "区域控制器")
public class RegionController implements ReactiveServiceCrudController<Region, String> {

    @Getter
    @Autowired
    private RegionService service;

    @Autowired
    private RegionDeviceService regionDeviceService;

    public RegionController(RegionService regionService) {
        this.service = regionService;
    }

    /**
     * 获取所有区域的树形数据
     *
     * @return 区域的树形数据
     */
    @GetMapping("/_all/tree")
    @Authorize(merge = false)
    @Operation(summary = "获取全部区域信息(树结构)")
    public Flux<Region> getAllRegionTree(@Parameter(hidden = true) QueryParamEntity entity) {
        log.info("调用了。getAllRegionTree。 ");
        return entity
            .toNestQuery()
            .execute(Mono::just)
            .as(service::queryPager)
            .flatMapIterable(list -> TreeSupportEntity.list2tree(list.getData(), Region::setChildren));
    }

    @GetMapping("/_query/_children/tree")
    @QueryAction
    @QueryOperation(summary = "查询区域列表(包含子区域)树结构")
    public Mono<List<Region>> queryChildrenTree(@Parameter(hidden = true) QueryParamEntity entity) {
        return entity
            .toNestQuery()
            .execute(service::queryIncludeChildrenTree);
    }

    @GetMapping("/_query/_children")
    @QueryAction
    @QueryOperation(summary = "查询区域列表(包含子区域)")
    public Flux<Region> queryChildren(@Parameter(hidden = true) QueryParamEntity entity) {
        return entity
            .toNestQuery()
            .execute(service::queryIncludeChildren);
    }

    @PostMapping("/{id}/devices/_bind")
    @ResourceAction(id = "bind-device", name = "绑定设备")
    @Operation(summary = "绑定设备到区域")
    public Mono<Integer> bindDevice(@Parameter(description = "区域ID") @PathVariable String regionId,
                                  @Parameter(description = "设备ID")
                                  @RequestBody Mono<List<String>> deviceId) {

        return deviceId
            .flatMapIterable(Function.identity())
            .map(dId -> {
                RegionDeviceEntity relEntity = new RegionDeviceEntity();
                relEntity.setDeviceId(dId);
                relEntity.setRegionId(regionId);
                return relEntity;
            })
            .as(regionDeviceService::save)
            .map(SaveResult::getTotal);

    }

    @PostMapping("/{id}/devices/_unbind")
    @ResourceAction(id = "unbind-device", name = "解绑设备")
    @Operation(summary = "从区域解绑设备")
    public Mono<Integer> unbindDevice(@Parameter(description = "区域ID") @PathVariable String id,
                                    @Parameter(description = "设备ID")
                                    @RequestBody Mono<List<String>> deviceId) {
        return deviceId
            .flatMap(newUserIdList -> regionDeviceService
                .createDelete()
                .where(RegionDeviceEntity::getRegionId, id)
                .in(RegionDeviceEntity::getDeviceId, newUserIdList)
                .execute());
    }

}
